use core::{ffi::c_void, ptr::null_mut};

use mlibs::cmsis_rtos2::thread::{Thread, PRIORITY_HIGH, THREAD_DETACHED};

use crate::{driver::cmd_uart::CMD_UART, proto::{make_empty, make_res_empty, uart_log, CmdFrame, ProtoReceiver, StreamBuf, CMD_OTA_COMPLETE, CMD_OTA_START, CMD_OTA_TRANSLATE, TYPE_PING, TYPE_PONG, TYPE_SIMPLE_REQ, TYPE_SIMPLE_RES}, service::ota, task::status_task};


static APP_TASK: Thread<2048, PRIORITY_HIGH, THREAD_DETACHED> = Thread::const_new();

pub unsafe fn start() {
    APP_TASK.create("app_task", task_run, null_mut());
}

static RECEIVER: ProtoReceiver<255> = ProtoReceiver::const_new();


extern "C"
fn task_run(_: *mut c_void) {
    CMD_UART.init();
    
    defmt::println!("app run");
    status_task::start();
    
    uart_log("app run");
    let mut stream = StreamBuf::new(&CMD_UART);

    loop {
        let frame = RECEIVER.recv(&mut stream);
        match frame.ctype() {
            TYPE_PING => {
                CMD_UART.write(&make_empty(TYPE_PONG, frame.seq()));
            }
            TYPE_SIMPLE_REQ => {
                on_simple_req(frame.into());
            }
            _ => {}
        }
    }
}

fn on_simple_req(frame: CmdFrame) {
 //   defmt::println!("simple req:{}", frame.cmd());

    let ret = match frame.cmd() {
        CMD_OTA_START => ota::on_start(&frame),
        CMD_OTA_TRANSLATE => ota::on_translate(&frame),
        CMD_OTA_COMPLETE => ota::on_complete(&frame),
        _ => return
    };

    let Err(err) = ret else {
        return;
    };

    if let Err(_) = CMD_UART.send(TYPE_SIMPLE_RES, frame.seq(), 1, &err.other_msg()) {
        defmt::println!("write res err",);
    }
}
